package com.kindey.redissen.conf;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import cn.hutool.core.lang.Validator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.util.CollectionUtils;

import java.time.Duration;
import java.util.Arrays;
import java.util.List;

/**
 * 作用描述
 *
 * @author Kindey.S [kindey123@163.com]
 * @version 1.0
 * @date 2023/9/6
 */
@Configuration
@Slf4j
public class RedisConfig {
    @Value("${spring.data.redis.sentinel.database}")
    int database;
    @Value("${spring.data.redis.sentinel.password}")
    String password;
    @Value("${spring.data.redis.sentinel.master}")
    String master;
    @Value("${spring.data.redis.sentinel.nodes}")
    List<String> nodes;

    @Value("${spring.data.redis.lettuce.pool.max-idle}")
    int maxIdle;
    @Value("${spring.data.redis.lettuce.pool.max-active}")
    int maxActive;
    @Value("${spring.data.redis.lettuce.pool.min-idle}")
    int minIdle;
    @Value("${spring.data.redis.lettuce.pool.max-wait}")
    long maxWait;

    @Bean
    public RedisConnectionFactory lettuceConnectionFactory() {
        RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration();
        if (StringUtils.isEmpty(master)) {
            master = "mymaster";
        }
        sentinelConfig.setMaster(master);
        if (CollectionUtils.isEmpty(nodes)) {
            RedisNode redisNode = new RedisNode("127.0.0.1", 26379);
            sentinelConfig.addSentinel(redisNode);
        }
        for (String node : nodes) {
            String[] hostInfo = node.split(":");
            if (CollectionUtils.isEmpty(Arrays.asList(hostInfo))) {
                throw new RuntimeException("哨兵地址不能为空");
            } else if (hostInfo.length == 1) {
                if(!Validator.isIpv4(hostInfo[0])){
                    throw new RuntimeException("无效的哨兵IP："+node);
                } else {
                    RedisNode redisNode = new RedisNode(hostInfo[0], 26379);
                    sentinelConfig.addSentinel(redisNode);
                }
            } else if (hostInfo.length == 2){
                RedisNode redisNode = new RedisNode(hostInfo[0], Integer.parseInt(hostInfo[1]));
                sentinelConfig.addSentinel(redisNode);
            } else {
                throw new RuntimeException("错误的哨兵连接地址：" + node);
            }
        }
        sentinelConfig.setDatabase(database);
        if (StringUtils.isNotEmpty(password)) {
            sentinelConfig.setPassword(password);
        }

        GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
        if (maxIdle == 0) {
            maxIdle = 10;
        }
        genericObjectPoolConfig.setMaxIdle(maxIdle);
        genericObjectPoolConfig.setMinIdle(minIdle);
        if (maxActive == 0) {
            maxActive = 20;
        }
        genericObjectPoolConfig.setMaxTotal(maxActive);
        if (maxWait == 0) {
            maxWait = 10 * 1000;
        }
        genericObjectPoolConfig.setMaxWaitMillis(maxWait);

        //redis客户端配置
        LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder builder =
                LettucePoolingClientConfiguration.builder().commandTimeout(Duration.ofMillis(maxWait));

        builder.shutdownTimeout(Duration.ofMillis(maxWait));
        builder.poolConfig(genericObjectPoolConfig);
        LettuceClientConfiguration clientConfig = builder.build();


        return new LettuceConnectionFactory(sentinelConfig, clientConfig);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        // 将template 泛型设置为 <String, Object>
        RedisTemplate<String, Object> template = new RedisTemplate();
        // 连接工厂，不必修改
        template.setConnectionFactory(redisConnectionFactory);
        // key、hash的key 采用 String序列化方式
        template.setKeySerializer(RedisSerializer.string());
        template.setHashKeySerializer(RedisSerializer.string());
        // value、hash的value 采用 Jackson 序列化方式
        template.setValueSerializer(RedisSerializer.json());
        template.setHashValueSerializer(RedisSerializer.json());
        template.afterPropertiesSet();

        return template;
    }
}
